
#pragma once

#include <stdio.h>
#include <exception>
#include <string>

namespace ct
{

    class exception : std::exception
    {
    public:
        std::string msg;

        exception(const char *m) : msg(m)
        {
        }
    };

    class c_test
    {
    public:
        int success = 0;
        int failed = 0;
        std::string name;
        c_test(const std::string &_name) : name(_name)
        {
        }
        virtual void main() {}
        static void add(c_test *ptr);
        virtual ~c_test() {}
    };

#define CTEST_BEGIN(name)                                             \
    namespace                                                         \
    {                                                                 \
        class childc_test##name : private ct::c_test                  \
        {                                                             \
        private:                                                      \
        public:                                                       \
            typedef childc_test##name this_class;                     \
            childc_test##name(const std::string &name) : c_test(name) \
            {                                                         \
                c_test::add(this);                                    \
            }

#define CTEST_END(name)      \
    }                        \
    g_test_obj##name(#name); \
    }

    void c_test_run_all(void);
    void c_test_cleanup(void);

#define __const_2_str_x(x) #x
#define __const_2_str(x) __const_2_str_x(x)

#define CT_ASSERT(cond)                                                                         \
    if (!(cond))                                                                                \
    {                                                                                           \
        this->failed++;                                                                         \
        throw ct::exception("\n" __FILE__ ":" __const_2_str(__LINE__) " assert failed:" #cond); \
    }                                                                                           \
    else                                                                                        \
    {                                                                                           \
        this->success++;                                                                        \
    }

#define CT_ASSERT_EQ(a, b)                                                                                    \
    do                                                                                                        \
    {                                                                                                         \
        if (!((a) == (b)))                                                                                    \
        {                                                                                                     \
            this->failed++;                                                                                   \
            printf("\n" __FILE__ ":" __const_2_str(__LINE__) "  \033[31m%d vs %d Failed.\033[0m ", (a), (b)); \
            throw ct::exception("\n" __FILE__ ":" __const_2_str(__LINE__) " assert failed:" #a " == " #b);    \
        }                                                                                                     \
        else                                                                                                  \
        {                                                                                                     \
            this->success++;                                                                                  \
        }                                                                                                     \
    } while (0)

#define CT_EQI(a, b)                                                                                          \
    do                                                                                                        \
    {                                                                                                         \
        if ((a) != (b))                                                                                       \
        {                                                                                                     \
            this->failed++;                                                                                   \
            printf("\n" __FILE__ ":" __const_2_str(__LINE__) "  \033[31m%d vs %d Failed.\033[0m ", (a), (b)); \
        }                                                                                                     \
        else                                                                                                  \
        {                                                                                                     \
            this->success++;                                                                                  \
        }                                                                                                     \
    } while (0)
#define CT_EQS(a, b)                                                                                                          \
    do                                                                                                                        \
    {                                                                                                                         \
        if ((a) != (b))                                                                                                       \
        {                                                                                                                     \
            this->failed++;                                                                                                   \
            printf("\n" __FILE__ ":" __const_2_str(__LINE__) "  \033[31m%s vs %s Failed.\033[0m ", (a).c_str(), (b).c_str()); \
        }                                                                                                                     \
        else                                                                                                                  \
        {                                                                                                                     \
            this->success++;                                                                                                  \
        }                                                                                                                     \
    } while (0)
#define CT_CHECK(cond)                                                                                \
    do                                                                                                \
    {                                                                                                 \
        if (!(cond))                                                                                  \
        {                                                                                             \
            this->failed++;                                                                           \
            printf("\n" __FILE__ ":" __const_2_str(__LINE__) "  \033[31m%s Failed.\033[0m\n", #cond); \
        }                                                                                             \
        else                                                                                          \
        {                                                                                             \
            this->success++;                                                                          \
        }                                                                                             \
    } while (0)

}